package packet

import (
	"bytes"
	"encoding/json"
	"math"
)

type FixPackAdapter struct {
	Info     AdapterInfo
	HeadSize int
	MinSize  int
}

func NewFix2Pack() *FixPackAdapter {
	out := FixPackAdapter{
		Info: AdapterInfo{
			MaxPackageSize: math.MaxUint16,
			Name:           Fixed2LengthAdapterName,
		},
		HeadSize: 2,
		MinSize:  1,
	}
	return &out
}
func NewFix4Pack() *FixPackAdapter {
	out := FixPackAdapter{
		Info: AdapterInfo{
			MaxPackageSize: math.MaxUint32,
			Name:           Fixed4LengthAdapterName,
		},
		HeadSize: 4,
		MinSize:  1,
	}
	return &out
}
func (adapter *FixPackAdapter) Name() string {
	if adapter.HeadSize == 2 {
		return Fixed2LengthAdapterName
	}
	if adapter.HeadSize == 4 {
		return Fixed4LengthAdapterName
	}
	return ""
}
func (adapter *FixPackAdapter) DumpString() string {
	if adapter == nil {
		return "invalidate adapter"
	}
	outByte, err := json.Marshal(adapter)
	if err == nil {
		var output bytes.Buffer
		if err := json.Indent(&output, outByte, "", "\t"); err != nil {
			return string(outByte)
		}

		return output.String()
	}
	return ""
}

func (adapter *FixPackAdapter) GenHeaderByLen(packageLen uint32) (outHeader []byte) {
	if packageLen > adapter.Info.MaxPackageSize {
		return nil
	}
	if adapter.HeadSize == 2 {
		outHeader = []byte{
			byte((packageLen & 0xFF00) >> 8),
			uint8(packageLen & 0x00FF),
		}
		return
	}
	if adapter.HeadSize == 4 {
		outHeader = []byte{
			byte((packageLen & 0xFF000000) >> 24),
			byte((packageLen & 0x00FF0000) >> 16),
			byte((packageLen & 0x0000FF00) >> 8),
			uint8(packageLen & 0x000000FF),
		}
		return
	}

	return nil
}

func (adapter *FixPackAdapter) GenHeader(orgPack []byte) (header []byte) {
	return adapter.GenHeaderByLen(uint32(len(orgPack)))
}

func (adapter *FixPackAdapter) PackNew(orgPack []byte) (newPackage []byte) {
	orgLen := len(orgPack)
	if orgLen < adapter.MinSize {
		return nil
	}
	header := adapter.GenHeader(orgPack)
	if header == nil {
		return nil
	}
	headerLen := len(header)
	newPackage = make([]byte, orgLen+headerLen)
	copy(newPackage[0:headerLen], header)
	copy(newPackage[headerLen:], orgPack)
	return
}
func (adapter *FixPackAdapter) PackTo(originPackage []byte, outPackage []byte, withPayload bool) (copiedSize int) {
	orgLen := len(originPackage)
	if orgLen < adapter.MinSize {
		return 0
	}
	header := adapter.GenHeader(originPackage)
	if header == nil {
		return 0
	}
	headerLen := len(header)
	copy(outPackage[0:headerLen], header)
	if withPayload {
		copy(outPackage[headerLen:], originPackage)
		return headerLen + len(originPackage)
	}
	return headerLen
}

func (adapter *FixPackAdapter) UnPack(inputPackage []byte) (originSize uint32, payloadOffset int32) {
	inputLen := len(inputPackage)
	if inputLen < adapter.MinSize {
		return 0, -1
	}
	if adapter.HeadSize == 2 {
		originSize = (uint32(inputPackage[0]) << 8) | (uint32(inputPackage[1]))
		payloadOffset = 2
		return
	}
	if adapter.HeadSize == 4 {
		originSize = (uint32(inputPackage[0]) << 24) | (uint32(inputPackage[1]) << 16) | (uint32(inputPackage[2]) << 8) | (uint32(inputPackage[3]))
		payloadOffset = 4
		return
	}

	return 0, -1
}
